/**
 * @file STL_Json.cpp
 * @author Derek Liu (yjkhtddx@sina.com)
 * @brief 
 * @version 0.1
 * @date 2020-09-10
 * 
 * @copyright Copyright Sci-Tech Laboratories (c) 2020
 * 
 */

#include "STL_Json.h"

#include <iostream>
#include <memory> //std::unique_ptr

namespace STL
{

    JSONCPP::Value sliceArray(JSONCPP::Value array, int pos, int len)
    {
        JSONCPP::Value ret = JSONCPP::Value(JSONCPP::ValueType::arrayValue);
        if (array.isArray())
        {
            for (int i = pos; i < array.size() && ret.size() < len; i++)
            {
                ret.append(array[i]);
            }
        }
        return ret;
    }
    std::string getJsonString(Json::Value value, bool isStyled = false)
    {
        Json::StreamWriterBuilder writerBuilder;
        writerBuilder["emitUTF8"] = true;
        std::ostringstream os;
        if (!isStyled)
        {
            writerBuilder.settings_["indentation"] = "";
        }
        std::unique_ptr<Json::StreamWriter> jsonWriter(writerBuilder.newStreamWriter());
        jsonWriter->write(value, &os);
        return os.str();
    };

    bool getJsonObject(std::string jsonStr, Json::Value &value)
    {
        if (jsonStr.empty())
        {
            std::cout << "parseJsonFromString string empty! " << std::endl;
            return false;
        }
        JSONCPP_STRING errs;
        Json::CharReaderBuilder readerBuilder;
        std::unique_ptr<Json::CharReader> const jsonReader(readerBuilder.newCharReader());
        bool res = jsonReader->parse(jsonStr.c_str(), jsonStr.c_str() + jsonStr.length(), &value, &errs);
        if (!res || !errs.empty())
        {
            value = JSONCPP::Value(JSONCPP::ValueType::nullValue);
            std::cout << "parseJsonFromString error! " << errs << std::endl;
            return false;
        }
        return true;
    };

    std::string getFastString(JSONCPP::Value value)
    {
        JSONCPP::FastWriter writer;
        return writer.write(value);
        // return getJsonString(value, false);
    };

    std::string getStyledString(JSONCPP::Value value)
    {
        // JSONCPP::StyledWriter writer;
        // return writer.write(value);
        return getJsonString(value, true);
    };

    void printfJson(JSONCPP::Value value, std::string table)
    {
        printf("-------------------------------\n");
        printf("%s\n", table.c_str());
        printf("-------------------------------\n");
        printf("%s\n", getStyledString(value).c_str());
        printf("-------------------------------\n");
    };

    JSONCPP::Value getJsonFromString(std::string str)
    {
        // JSONCPP::Reader reader;
        // JSONCPP::Value value;
        // if (reader.parse(str, value))
        // {
        //     return value;
        // }
        // else
        // {
        //     value.clear();
        //     return value;
        // }
        JSONCPP::Value value(JSONCPP::ValueType::nullValue);
        getJsonObject(str, value);
        return value;
    };

    /**
     * @brief 合并两个json对象,有相同元素的话,以object1为主
     * 
     * @param object1 
     * @param object2 
     * @return JSONCPP::Value 
     */
    JSONCPP::Value unionJsonObject(JSONCPP::Value object1, JSONCPP::Value object2)
    {
        JSONCPP::Value object(JSONCPP::ValueType::objectValue);
        if (object1.isObject() && object2.isObject())
        {
            object = object2;
            //JSONCPP:Value::Members = std::vector<std::string>
            JSONCPP::Value::Members list = object1.getMemberNames();
            for (size_t i = 0; i < list.size(); i++)
            {
                object[list.at(i)] = object1[list.at(i)];
            }
            return object;
        }
        else if (object1.isObject())
        {
            return object1;
        }
        else if (object2.isObject())
        {
            return object2;
        }
        else
        {
            return object;
        }
    }

    JSONCPP::Value unionJsonArray(JSONCPP::Value array1, JSONCPP::Value array2)
    {
        JSONCPP::Value array(JSONCPP::ValueType::arrayValue);
        if (array1.isArray() && array2.isArray())
        {
            array = array1;
            for (size_t i = 0; i < array2.size(); i++)
            {
                JSONCPP::Value temp = array2[std::to_string(i)];
                array.append(temp);
            }
            return array;
        }
        else if (array1.isArray())
        {
            return array1;
        }
        else if (array2.isArray())
        {
            return array2;
        }
        else
        {
            return array;
        }
    }
    /**
     * @brief 检测对象类型参数错误
     * 
     * @param request 
     * @param key 
     * @return true 错误
     * @return false 正确
     */
    bool checkIsMissObject(JSONCPP::Value &object, std::string key)
    {
        if (object.isObject())
            return (!object.isMember(key) || !object[key].isObject());
        return false;
    }
    /**
     * @brief 检测数组类型参数错误
     * 
     * @param request 
     * @param key 
     * @return true 错误
     * @return false 正确
     */
    bool checkIsMissArray(JSONCPP::Value &object, std::string key)
    {
        if (object.isObject())
            return (!object.isMember(key) || !object[key].isArray());
        return false;
    }
    /**
     * @brief 检测字符串类型参数错误
     * 
     * @param request 
     * @param key 
     * @return true 错误
     * @return false 正确
     */
    bool checkIsMissString(JSONCPP::Value &object, std::string key)
    {
        if (object.isObject())
            return (!object.isMember(key) || !object[key].isString());
        return false;
    }

    /**
     * @brief 检测数字类型参数错误
     * 
     * @param request 
     * @param key 
     * @return true 错误
     * @return false 正确
     */
    bool checkIsMissNumber(JSONCPP::Value &object, std::string key)
    {
        if (object.isObject())
            return (!object.isMember(key) || !object[key].isNumeric());
        return false;
    }

    /**
     * @brief 检测整型参数错误
     * 
     * @param request 
     * @param key 
     * @return true 错误
     * @return false 正确
     */
    bool checkIsMissInt(JSONCPP::Value &object, std::string key)
    {
        if (object.isInt())
            return (!object.isMember(key) || !object[key].isInt());
        return false;
    }

    /**
     * @brief 检测布尔类型参数错误
     * 
     * @param request 
     * @param key 
     * @return true 错误
     * @return false 正确
     */
    bool checkIsMissBool(JSONCPP::Value &object, std::string key)
    {
        if (object.isObject())
            return (!object.isMember(key) || !object[key].isBool());
        return false;
    }
    JSONCPP::Value clearNullOfObject(JSONCPP::Value &object)
    {
        JSONCPP::Value ret(JSONCPP::ValueType::objectValue);
        if (!object.isObject())
            return ret;
        JSONCPP::Value::Members list = object.getMemberNames();
        for (size_t i = 0; i < list.size(); i++)
        {
            if (!object[list.at(i)].isNull())
            {
                ret[list.at(i)] = object[list.at(i)];
            }
        }
        return ret;
    }
} // namespace STL